home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / os2 / gnuwget.zip / wget-1.4.3 / src / ftp-basic.c < prev    next >
C/C++ Source or Header  |  1997-01-28  |  12KB  |  548 lines

  1. /* Basic FTP routines.
  2.    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.    
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18.  
  19. #ifdef HAVE_CONFIG_H
  20. #  include <config.h>
  21. #endif /* HAVE_CONFIG_H */
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #ifdef HAVE_STRING_H
  26. #  include <string.h>
  27. #else
  28. #  include <strings.h>
  29. #endif
  30. #include <ctype.h>
  31. #ifdef HAVE_UNISTD_H
  32. #  include <unistd.h>
  33. #endif
  34. #include <sys/types.h>
  35.  
  36. #ifdef WINDOWS
  37. #  include <winsock.h>
  38. #endif
  39.  
  40. #include "wget.h"
  41. #include "options.h"
  42. #include "utils.h"
  43. #include "ftp-basic.h"
  44. #include "connect.h"
  45. #include "host.h"
  46. #include "retr.h"
  47.  
  48. extern struct options opt;
  49.  
  50. #ifndef errno
  51. extern int errno;
  52. #endif
  53. #ifndef h_errno
  54. extern int h_errno;
  55. #endif
  56.  
  57. char ftp_last_respline[128];
  58.  
  59. /* Get the response of FTP server and allocate enough room to handle
  60.    it.  <CR> and <LF> characters are stripped from the line, and the
  61.    line is 0-terminated.  All the response lines but the last one are
  62.    skipped. The last line is determined as described in RFC959. */
  63. uerr_t
  64. ftp_response(int fd, char **line)
  65. {
  66.    int i, bufsize, res;
  67.    
  68.    bufsize = DYNAMIC_LINE_BUFFER;
  69.    *line = nmalloc(bufsize);
  70.    do
  71.    {
  72.       for (i = 0; 1; i++)
  73.       {
  74.      if (i > bufsize - 1)
  75.         *line = (char *)nrealloc(*line, (bufsize <<= 1));
  76.      res = buf_readchar(fd, *line + i);
  77.      /* res is number of bytes read. */
  78.      if (res == 1)
  79.      {
  80.         if ((*line)[i] == '\n')
  81.         {
  82.            (*line)[i] = '\0';
  83.            /* Get rid of \r. */
  84.            if (i > 0 && (*line)[i - 1] == '\r')
  85.           (*line)[i - 1] = '\0';
  86.            break;
  87.         }
  88.      }
  89.      else
  90.         return FTPRERR;
  91.       }
  92. #ifdef DEBUG
  93.       if (opt.debug && !opt.server_response)
  94.      fprintf(opt.lfile, "%s\n", *line);
  95. #endif
  96.       if (opt.server_response)
  97.      fprintf(opt.lfile, "%s\n", *line);
  98.    } while (!(i >= 3 && isdigit(**line) && isdigit((*line)[1]) &&
  99.           isdigit((*line)[2]) && (*line)[3] == ' '));
  100.    strncpy(ftp_last_respline, *line, 128);
  101.    ftp_last_respline[127] = '\0';
  102.    return FTPOK;
  103. }
  104.  
  105. /* Returns the malloc-ed FTP request, ending with <CR><LF>, printing
  106.    it if printing is required.  If VALUE is NULL, just use
  107.    command<CR><LF>.  */
  108. char *
  109. ftp_request(const char *command, const char *value)
  110. {
  111.    char *res;
  112.  
  113.    res = (char *)nmalloc(strlen(command)
  114.              + (value ? (1 + strlen(value)) : 0) + 2 + 1);
  115.    sprintf(res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
  116. #ifdef DEBUG
  117.    if (opt.debug && !opt.server_response)
  118.       fprintf(opt.lfile, "\n--> %s\n", res);
  119. #endif
  120.    if (opt.server_response)
  121.    {
  122.       /* We don't want to print out passwords: */
  123.       if (strncmp(res, "PASS", 4) != 0)
  124.      fprintf(opt.lfile, "--> %s\n", res);
  125.       else
  126.      fprintf(opt.lfile, "--> PASS Turtle Power!\n");
  127.    }
  128.    return res;
  129. }
  130.  
  131. /* Sends the USER and PASS commands to the server, to control
  132.    connection socket csock. */
  133. uerr_t
  134. ftp_login(int csock, const char *acc, const char *pass)
  135. {
  136.    uerr_t err;
  137.    char *request, *respline;
  138.    int nwritten;
  139.  
  140.    /* Get greeting. */
  141.    err = ftp_response(csock, &respline);
  142.    if (err != FTPOK)
  143.    {
  144.       free(respline);
  145.       return err;
  146.    }
  147.    if (*respline != '2')
  148.    {
  149.       free(respline);
  150.       return FTPSRVERR;
  151.    }
  152.    free(respline);
  153.    /* Send USER username. */
  154.    request = ftp_request("USER", acc);
  155.    nwritten = iwrite(csock, request, strlen(request));
  156.    if (nwritten != strlen(request))
  157.    {
  158.       free(request);
  159.       return WRITEFAILED;
  160.    }
  161.    free(request);
  162.    /* Get appropriate response. */
  163.    err = ftp_response(csock, &respline);
  164.    if (err != FTPOK)
  165.    {
  166.       free(respline);
  167.       return err;
  168.    }
  169.    /* An unprobable possibility of logging without a password. */
  170.    if (*respline == '2')
  171.    {
  172.       free(respline);
  173.       return FTPOK;
  174.    }
  175.    /* Else, only response 3 is appropriate. */
  176.    if (*respline != '3')
  177.    {
  178.       free(respline);
  179.       return FTPLOGREFUSED;
  180.    }
  181.    free(respline);
  182.    /* Send PASS password. */
  183.    request = ftp_request("PASS", pass);
  184.    nwritten = iwrite(csock, request, strlen(request));
  185.    if (nwritten != strlen(request))
  186.    {
  187.       free(request);
  188.       return WRITEFAILED;
  189.    }
  190.    free(request);
  191.    /* Get appropriate response. */
  192.    err = ftp_response(csock, &respline);
  193.    if (err != FTPOK)
  194.    {
  195.       free(respline);
  196.       return err;
  197.    }
  198.    if (*respline != '2')
  199.    {
  200.       free(respline);
  201.       return FTPLOGINC;
  202.    }
  203.    free(respline);
  204.    /* All OK. */
  205.    return FTPOK;
  206. }
  207.  
  208. /* Binds a port, and sends the appropriate PORT command to the FTP
  209.    server. Use acceptport after RETR, to get the socket of data
  210.    connection. */
  211. uerr_t
  212. ftp_port(int csock)
  213. {
  214.    uerr_t err;
  215.    char *request, *respline, *bytes;
  216.    unsigned char *in_addr;
  217.    int nwritten;
  218.    unsigned short port;
  219.  
  220.    /* Setting port to 0 lets the system choose a free port. */
  221.    port = 0;
  222.    /* Bind the port. */
  223.    err = bindport(&port);
  224.    if (err != BINDOK)
  225.       return err;
  226.    /* Get the address of this side of the connection. */
  227.    if (!(in_addr = conaddr(csock)))
  228.       return HOSTERR;
  229.    /* Construct the argument of PORT (of the form a,b,c,d,e,f) */
  230.    bytes = (char *)nmalloc(6 * 4 + 1);
  231.    sprintf(bytes, "%d,%d,%d,%d,%d,%d", in_addr[0], in_addr[1],
  232.        in_addr[2], in_addr[3], (unsigned)(port & 0xff00) >> 8,
  233.        port & 0xff);
  234.    /* Send PORT request. */
  235.    request = ftp_request("PORT", bytes);
  236.    free(bytes);
  237.    nwritten = iwrite(csock, request, strlen(request));
  238.    if (nwritten != strlen(request))
  239.    {
  240.       free(request);
  241.       return WRITEFAILED;
  242.    }
  243.    free(request);
  244.    /* Get appropriate response. */
  245.    err = ftp_response(csock, &respline);
  246.    if (err != FTPOK)
  247.    {
  248.       free(respline);
  249.       return err;
  250.    }
  251.    if (*respline != '2')
  252.    {
  253.       free(respline);
  254.       return FTPPORTERR;
  255.    }
  256.    free(respline);
  257.    return FTPOK;
  258. }
  259.  
  260. /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
  261.    transfer.  Reads the response from server and parses it.  Reads the
  262.    host and port addresses and returns them. */
  263. uerr_t
  264. ftp_pasv(int csock, unsigned char *addr)
  265. {
  266.    char *request, *respline;
  267.    unsigned char *s;
  268.    int nwritten, i;
  269.    uerr_t err;
  270.    
  271.    /* Form the request. */
  272.    request = ftp_request("PASV", NULL);
  273.    /* And send it. */
  274.    nwritten = iwrite(csock, request, strlen(request));
  275.    if (nwritten != strlen(request))
  276.    {
  277.       free(request);
  278.       return WRITEFAILED;
  279.    }
  280.    free(request);
  281.    /* Get the server response. */
  282.    err = ftp_response(csock, &respline);
  283.    if (err != FTPOK)
  284.    {
  285.       free(respline);
  286.       return err;
  287.    }
  288.    if (*respline != '2')
  289.    {
  290.       free(respline);
  291.       return FTPNOPASV;
  292.    }
  293.    /* Parse the request. */
  294.    s = (unsigned char *)respline;
  295.    for (s += 4; *s && !isdigit(*s); s++);
  296.    if (!*s)
  297.       return FTPINVPASV;
  298.    for (i = 0; i < 6; i++)
  299.    {
  300.       addr[i] = 0;
  301.       for (; isdigit(*s); s++)
  302.      addr[i] = (*s - '0') + 10 * addr[i];
  303.       if (*s == ',')
  304.      s++;
  305.       else if (i < 5)
  306.       {
  307.      /* When on the last number, anything can be a terminator. */
  308.      free(respline);
  309.      return FTPINVPASV;
  310.       }
  311.    }
  312.    free(respline);
  313.    return FTPOK;
  314. }
  315.  
  316. /* Sends the TYPE request to the server. */
  317. uerr_t
  318. ftp_type(int csock, int type)
  319. {
  320.    char *request, *respline;
  321.    int nwritten;
  322.    uerr_t err;
  323.    char stype[2];
  324.  
  325.    /* Construct argument. */
  326.    stype[0] = type;
  327.    stype[1] = 0;
  328.    /* Send TYPE request. */
  329.    request = ftp_request("TYPE", stype);
  330.    nwritten = iwrite(csock, request, strlen(request));
  331.    if (nwritten != strlen(request))
  332.    {
  333.       free(request);
  334.       return WRITEFAILED;
  335.    }
  336.    free(request);
  337.    /* Get appropriate response. */
  338.    err = ftp_response(csock, &respline);
  339.    if (err != FTPOK)
  340.    {
  341.       free(respline);
  342.       return err;
  343.    }
  344.    if (*respline != '2')
  345.    {
  346.       free(respline);
  347.       return FTPUNKNOWNTYPE;
  348.    }
  349.    free(respline);
  350.    /* All OK. */
  351.    return FTPOK;
  352. }
  353.  
  354. /* Changes the working directory by issuing a CWD command to the
  355.    server. */
  356. uerr_t
  357. ftp_cwd(int csock, const char *dir)
  358. {
  359.    char *request, *respline;
  360.    int nwritten;
  361.    uerr_t err;
  362.  
  363.    /* Send CWD request. */
  364.    request = ftp_request("CWD", dir);
  365.    nwritten = iwrite(csock, request, strlen(request));
  366.    if (nwritten != strlen(request))
  367.    {
  368.       free(request);
  369.       return WRITEFAILED;
  370.    }
  371.    free(request);
  372.    /* Get appropriate response. */
  373.    err = ftp_response(csock, &respline);
  374.    if (err != FTPOK)
  375.    {
  376.       free(respline);
  377.       return err;
  378.    }
  379.    if (*respline == '5')
  380.    {
  381.       free(respline);
  382.       return FTPNSFOD;
  383.    }
  384.    if (*respline != '2')
  385.    {
  386.       free(respline);
  387.       return FTPRERR;
  388.    }
  389.    free(respline);
  390.    /* All OK. */
  391.    return FTPOK;
  392. }
  393.  
  394. /* Sends REST command to the FTP server. */
  395. uerr_t
  396. ftp_rest(int csock, long offset)
  397. {
  398.    char *request, *respline;
  399.    int nwritten;
  400.    uerr_t err;
  401.    static char buf[20]; /* Buffer for the number */
  402.  
  403.    sprintf(buf, "%ld", offset);
  404.    request = ftp_request("REST", buf);
  405.    nwritten = iwrite(csock, request, strlen(request));
  406.    if (nwritten != strlen(request))
  407.    {
  408.       free(request);
  409.       return WRITEFAILED;
  410.    }
  411.    free(request);
  412.    /* Get appropriate response. */
  413.    err = ftp_response(csock, &respline);
  414.    if (err != FTPOK)
  415.    {
  416.       free(respline);
  417.       return err;
  418.    }
  419.    if (*respline != '3')
  420.    {
  421.       free(respline);
  422.       return FTPRESTFAIL;
  423.    }
  424.    free(respline);
  425.    /* All OK. */
  426.    return FTPOK;
  427. }
  428.  
  429. /* Sends RETR command to the FTP server. */
  430. uerr_t
  431. ftp_retr(int csock, const char *file)
  432. {
  433.    char *request, *respline;
  434.    int nwritten;
  435.    uerr_t err;
  436.  
  437.    /* Send RETR request. */
  438.    request = ftp_request("RETR", file);
  439.    nwritten = iwrite(csock, request, strlen(request));
  440.    if (nwritten != strlen(request))
  441.    {
  442.       free(request);
  443.       return WRITEFAILED;
  444.    }
  445.    free(request);
  446.    /* Get appropriate response. */
  447.    err = ftp_response(csock, &respline);
  448.    if (err != FTPOK)
  449.    {
  450.       free(respline);
  451.       return err;
  452.    }
  453.    if (*respline == '5')
  454.    {
  455.       free(respline);
  456.       return FTPNSFOD;
  457.    }
  458.    if (*respline != '1')
  459.    {
  460.       free(respline);
  461.       return FTPRERR;
  462.    }
  463.    free(respline);
  464.    /* All OK. */
  465.    return FTPOK;
  466. }
  467.  
  468. /* Sends the LIST command to the server.  If FILE is NULL, send just
  469.    `LIST' (no space).  */
  470. uerr_t
  471. ftp_list(int csock, const char *file)
  472. {
  473.    char *request, *respline;
  474.    int nwritten;
  475.    uerr_t err;
  476.  
  477.    /* Send LIST request. */
  478.    request = ftp_request("LIST", file);
  479.    nwritten = iwrite(csock, request, strlen(request));
  480.    if (nwritten != strlen(request))
  481.    {
  482.       free(request);
  483.       return WRITEFAILED;
  484.    }
  485.    free(request);
  486.    /* Get appropriate respone. */
  487.    err = ftp_response(csock, &respline);
  488.    if (err != FTPOK)
  489.    {
  490.       free(respline);
  491.       return err;
  492.    }
  493.    if (*respline == '5')
  494.    {
  495.       free(respline);
  496.       return FTPNSFOD;
  497.    }
  498.    if (*respline != '1')
  499.    {
  500.       free(respline);
  501.       return FTPRERR;
  502.    }
  503.    free(respline);
  504.    /* All OK. */
  505.    return FTPOK;
  506. }
  507.  
  508. /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
  509.    the string, and return the number converted to long, if found, 0
  510.    otherwise.  */
  511. long
  512. ftp_expected_bytes(const char *s)
  513. {
  514.    long res;
  515.  
  516.    do
  517.    {
  518.       while (*s && *s != '(')
  519.      ++s;
  520.       if (!*s)
  521.      return 0;
  522.       for (++s; *s && isspace(*s); s++);
  523.       if (!*s)
  524.      return 0;
  525.       if (!isdigit(*s))
  526.      continue;
  527.       res = 0;
  528.       do
  529.       {
  530.      res = (*s - '0') + 10 * res;
  531.      ++s;
  532.       } while (*s && isdigit(*s));
  533.       if (!*s)
  534.      return 0;
  535.       while (*s && isspace(*s))
  536.      ++s;
  537.       if (!*s)
  538.      return 0;
  539.       if (tolower(*s) != 'b')
  540.      continue;
  541.       if (strncasecmp(s, "byte", 4))
  542.      continue;
  543.       else
  544.      break;
  545.    } while (1);
  546.    return res;
  547. }
  548.